﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text; 
using System.Timers;

namespace Client
{


    class Program
    {
        #region Key event handler
        delegate bool ConsoleCtrlDelegate(int dwCtrlType);

        [DllImport("kernel32.dll")]
        static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate handlerRoutine, bool add);

        private const int CtrlCEvent = 0;//CTRL_C_EVENT = 0;//一个Ctrl+C的信号被接收，该信号或来自键盘，或来自GenerateConsoleCtrlEvent    函数   

        private const int CtrlBreakEvent = 1;//CTRL_BREAK_EVENT = 1;//一个Ctrl+Break信号被接收，该信号或来自键盘，或来自GenerateConsoleCtrlEvent    函数  

        private const int CtrlCloseEvent = 2;//CTRL_CLOSE_EVENT = 2;//当用户系统关闭Console时，系统会发送此信号到此   

        private const int CtrlLogoffEvent = 5;//CTRL_LOGOFF_EVENT = 5;//当用户退出系统时系统会发送这个信号给所有的Console程序。该信号不能显示是哪个用户退出。   

        private const int CtrlShutdownEvent = 6;//CTRL_SHUTDOWN_EVENT = 6;//当系统将要关闭时会发送此信号到所有Console程序   

        static bool HandlerRoutine(int ctrlType)
        {
            switch (ctrlType)
            {
                case CtrlCEvent:
                    Console.WriteLine("Control-C\n^C");
                    Environment.Exit(0);
                    return true;

                case CtrlBreakEvent: System.Console.WriteLine("Ctrl+Break keydown"); break;

                case CtrlCloseEvent: System.Console.WriteLine("window closed"); break;

                case CtrlLogoffEvent: System.Console.WriteLine("log off or shut down"); break;

                case CtrlShutdownEvent: System.Console.WriteLine("system shut down"); break;

                default: System.Console.WriteLine(ctrlType.ToString()); break;
            }

            return false;
        }

        static void SetKeyHandler()
        {
            if (SetConsoleCtrlHandler(new ConsoleCtrlDelegate(HandlerRoutine), true))
            {
                Debug.WriteLine("Set    SetConsoleCtrlHandler    success!!");
            }
            else
            {
                Debug.WriteLine("Set    SetConsoleCtrlHandler    Error!!");
            }
        }
        #endregion


        #region Fields
        static Timer timer;
        static string _keyCode; 
        static int frequency; //发送频率 frequency秒/次
        static List<int> keys = new List<int>();
        static IntPtr handler; //要控制的程序的handler
        #endregion


        #region Dllimports
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(
            string lpClassName, // class name 
            string lpWindowName // window name
            );

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(
            IntPtr hwndParent,
            IntPtr hwndChildAfter,
            string lpszClass,
            string lpszWindow
        );

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool PostMessage(
            IntPtr hWnd, // handle to destination window
            UInt32 Msg, // message
            Int32 wParam, // first message parameter
            Int32 lParam // second message parameter
        );

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        #endregion

        // Client -p [pid] -n [name] -k [key] -f [frequency]

        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine($"Client [Version {Utils.GetVersion()}]\n");
              
            if (args.Length == 0)
            {
                GetConfig();
            }
            else
            {
                ResolveParameters(args);
                Console.WriteLine($"key: {_keyCode} frequency: {frequency}");
                
            }

            SetKeyHandler();

            SendKey();

            timer = new Timer(frequency * 1000)
            {
                Enabled = true
            };

            timer.Elapsed += Timer_Elapsed;
            timer.Start();

            System.Windows.Forms.Application.Run();
        }

        // 解析参数
        private static void ResolveParameters(string[] args)
        {
            var arguments = CommandLineArgumentParser.Parse(args);
            if (arguments.Has("-p"))
            {
                string pid = arguments.Get("-p").Next.ToString();
                handler = GetWindowHandleByPid(Convert.ToInt32(pid));
                Console.WriteLine($"pid: {pid}");
            }
            else if (arguments.Has("-n"))
            {
                string name = arguments.Get("-n").Next.ToString();
                handler = GetWindowHandleByName(name);
                Console.WriteLine($"name: {name}");
            }
            else
            {

            }

            if (arguments.Has("-k"))
            {
                _keyCode = arguments.Get("-k").Next.ToString();
                string[] cmds = _keyCode.Split(',');

                for (int i = 0; i < cmds.Length; i++)
                {
                    keys.Add(Convert.ToInt32(cmds[i]));
                }
            }
            if (arguments.Has("-f"))
            {
                string freq = arguments.Get("-f").Next.ToString();
                Console.WriteLine($"frequency: {freq}");
                frequency = Convert.ToInt32(freq);
            }
        }

        static void SendKey()
        {
            foreach (var item in keys)
            {
                Console.WriteLine($"Command: {item}");
                Console.Out?.Flush();
                if (item.Equals(173))
                {
                    Mouse.Down(System.Windows.Input.MouseButton.Left);
                    Mouse.Up(System.Windows.Input.MouseButton.Left);
                }
                else if (item.Equals(174))
                {
                    Mouse.Down(System.Windows.Input.MouseButton.Right);
                    Mouse.Up(System.Windows.Input.MouseButton.Right);
                }
                else
                {
                    //KeyHelper.SendKey(item);
                    int keyCode = Convert.ToInt32(item);
                    System.Windows.Input.Key key = (System.Windows.Input.Key)keyCode;
                    Keyboard.Press(key);
                    //Keyboard.Release(key);
                }
            }

            foreach (var item in keys)
            {
                int keyCode = Convert.ToInt32(item);
                System.Windows.Input.Key key = (System.Windows.Input.Key)keyCode;
                Keyboard.Release(key);
            }
        }

        private static void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {  
            PostKey(handler);
        }

        static void GetConfig()
        {
            string text = FileHelper.ReadFile();
            if (!string.IsNullOrEmpty(text))
            {
                string[] contentLines = text.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); //忽略空行
                if (contentLines != null && contentLines.Length == 2)
                {
                    _keyCode = contentLines[0];
                    string[] cmds = _keyCode.Split(',');

                    for (int i = 0; i < cmds.Length; i++)
                    {
                        keys.Add(Convert.ToInt32(cmds[i]));
                    } 

                    frequency = Convert.ToInt32(contentLines[1]);
                }
                else
                {
                    _keyCode = "262144";
                    frequency = 1;
                }
            }
        }


        static IntPtr GetWindowHandleByName(string appName)
        {
            IntPtr windowHandle = IntPtr.Zero;
            Process[] processes = Process.GetProcessesByName(appName);
            if (processes.Length > 0)
            {
                windowHandle = processes[0].MainWindowHandle;
            }

            return windowHandle;
        }

        static IntPtr GetWindowHandleByPid(int pid)
        {
            IntPtr windowHandle = IntPtr.Zero;
            Process process = Process.GetProcessById(pid); 
            windowHandle = process.MainWindowHandle;
            return windowHandle;
        }

        static void PostKey(IntPtr hwnd)
        {
            const int WM_KEYDOWN = 0x100;
            const int WM_KEYUP = 0x101;
            const int WM_SYSKEYDOWN = 0x0104;
            const int WM_SYSKEYUP = 0x0105;

            IntPtr editx = FindWindowEx(handler, IntPtr.Zero, "edit", null);

            foreach (var item in keys)
            {
                Console.WriteLine($"{DateTime.Now}: key [{item}]");
                int keyCode = Convert.ToInt32(item);

                PostMessage(hwnd, WM_KEYDOWN, (int)Keys.ALT, 0);
                PostMessage(hwnd, WM_SYSKEYDOWN, (int)Keys.Tab, 0);
                //PostMessage(editx, WM_KEYDOWN, keyCode, 0);
                //PostMessage(editx, WM_KEYDOWN, keyCode, 0);
            }
             
            //foreach (var item in keys)
            //{
            //    int keyCode = Convert.ToInt32(item); 
            //    PostMessage(editx, WM_KEYUP, keyCode, 0);
            //    //PostMessage(editx, WM_SYSKEYUP, (int)Keys.ALT, 0);
            //    //PostMessage(editx, WM_KEYUP, keyCode, 0);
            //}

            Console.Out.Flush();
        }

        static void Command()
        {

        }
    }
}
